﻿//----------------------------------------------------------------
// Desc: 
// Edit: ShowLong, http://blog.csdn.net/showlong
//
// Date Created: 2012-04-13
//
// Update Date : 
//
// Copyright (c) Fuel4D (http://www.fuel4d.com), All rights reserved.
//
//----------------------------------------------------------------
#pragma once


#pragma pack(push, 1)


//----------------------------------------------------------------
// 
//----------------------------------------------------------------
class IFLockObject : public IFMemObject
{
public:
    enum LOCK_TYPE
    {
        eNil,
        eCS,
        eLinux,
        eVolatile,
        eEvent,
        eICE,
        eCAS,
    };

protected:
    explicit IFLockObject(LOCK_TYPE type)
        :nType(type)
    {}

public:
    // 获取当前锁的类型
    const IFLockObject::LOCK_TYPE GetType()
    {
        return nType;
    }
    // 锁定（直接进入）
    virtual void Lock() = 0;
    // 测试锁（如果当前不可锁则退出）
    virtual bool TryLock() = 0;
    // 解锁
    virtual void Unlock() = 0;

protected:
    const LOCK_TYPE nType;
};


//----------------------------------------------------------------
// 空锁
//----------------------------------------------------------------
class FLock_Nil : public IFLockObject
{
    FDECLARE_CLASS(FLock_Nil)

public:
    int _resive;
    FLock_Nil()
        :IFLockObject(eNil)
        ,_resive(0)
    {}
    virtual~FLock_Nil()
    {
        _resive = 0;
    }
    operator FLock_Nil* ()
    {
        return this;
    }
    virtual void Lock()
    {
        _resive = 1;
    }
    virtual bool TryLock()
    {
        _resive = 1;
        return true;
    }
    virtual void Unlock()
    {
        _resive = 0;
    }
};


//----------------------------------------------------------------
// 用于WIN32的
//----------------------------------------------------------------
#if FUEL_OS_WINDOWS
class FLock_CS : public IFLockObject
{
    FDECLARE_CLASS(FLock_CS)

public:
    CRITICAL_SECTION cs;
    FLock_CS()
        :IFLockObject(eCS)
    {
        InitializeCriticalSection(&cs);
    }
    virtual~FLock_CS()
    {
        DeleteCriticalSection(&cs);
    }
    operator FLock_CS* ()
    {
        return this;
    }
    virtual void Lock()
    {
        EnterCriticalSection(&cs);
    }
    virtual bool TryLock()
    {
        return TryEnterCriticalSection(&cs) == TRUE;
    }
    virtual void Unlock()
    {
        LeaveCriticalSection(&cs);
    }
};
#endif


//----------------------------------------------------------------
// 用于LINUX
//----------------------------------------------------------------
#if !(FUEL_OS_WINDOWS)
class FLock_linux : public IFLockObject
{
    FDECLARE_CLASS(FLock_linux)

public:
    pthread_mutex_t* mutex;
    pthread_mutexattr_t attr;
    FLock_linux()
        :IFLockObject(eLinux)
    	,mutex(0)
    {
    	mutex = new pthread_mutex_t;
    	mutex->value = __PTHREAD_MUTEX_INIT_VALUE;

    	pthread_mutexattr_init(&attr);
    	pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
    	pthread_mutex_init(mutex, &attr);
    }
    virtual~FLock_linux()
    {
    	pthread_mutexattr_destroy(&attr);
    	pthread_mutex_destroy(mutex);
    	delete mutex;
    }
    operator FLock_linux* ()
    {
        return this;
    }
    virtual void Lock()
    {
    	pthread_mutex_lock(mutex);
    }
    virtual bool TryLock()
    {
    	return pthread_mutex_trylock(mutex) == 0;
    }
    virtual void Unlock()
    {
    	pthread_mutex_unlock(mutex);
    }
};
#endif


//----------------------------------------------------------------
//
//----------------------------------------------------------------
class FLock_Volatile : public IFLockObject
{
    FDECLARE_CLASS(FLock_Volatile)

public:
    FVOLATILE long vol;
    FLock_Volatile()
        :IFLockObject(IFLockObject::eVolatile)
        ,vol(0)
    {}
    operator FLock_Volatile* ()
    {
        return this;
    }
    virtual void Lock()
    {
        while(vol)
            FSleep(1);
        FInterlockedIncrement(&vol);
    }
    virtual bool TryLock()
    {
        Lock();
        return true;
    }
    virtual void Unlock()
    {
        if (vol > 0)
            FInterlockedDecrement(&vol);
    }
};


//----------------------------------------------------------------
//
//----------------------------------------------------------------
#if FUEL_OS_WINDOWS
class FLock_Event : public IFLockObject
{
    FDECLARE_CLASS(FLock_Event)

public:
    HANDLE hevent;
    FLock_Volatile nvol;
    FLock_Event()
        :IFLockObject(IFLockObject::eEvent)
        ,hevent(CreateEvent(0, FALSE, TRUE, 0))
    {}
    virtual~FLock_Event()
    {
        if (hevent)
            CloseHandle(hevent);
    }
    operator FLock_Event* ()
    {
        return this;
    }
    virtual void Lock()
    {
        if (hevent)
            WaitForSingleObject(hevent, INFINITE);		
        else
            nvol.Lock();
    }
    virtual bool TryLock()
    {
        Lock();
        return true;
    }
    virtual void Unlock()
    {
        if (hevent)
            SetEvent(hevent);
        else
            nvol.Unlock();
    }
};
#endif


//----------------------------------------------------------------
//
//----------------------------------------------------------------
#if FUEL_OS_WINDOWS
class FLock_ICE : public IFLockObject
{
    FDECLARE_CLASS(FLock_ICE)

public:
    FVOLATILE long vol;
    FLock_ICE()
        :IFLockObject(IFLockObject::eICE)
        ,vol(0)
    {}
    operator FLock_ICE* ()
    {
        return this;
    }
    virtual void Lock()
    {
#if _MSC_VER > 1200
        while (1 == InterlockedCompareExchange(&vol, 1, 0))
            ;
#else
        int n = 1;
        while (1 == n)
            InterlockedCompareExchange((void**)&vol, (void*)&n, 0);
#endif
    }
    virtual bool TryLock()
    {
        Lock();
        return true;
    }
    virtual void Unlock()
    {
        vol = 0;
    }
};
#endif


//----------------------------------------------------------------
//
//----------------------------------------------------------------
#if FUEL_OS_WINDOWS
class FLock_CAS : public IFLockObject
{
    FDECLARE_CLASS(FLock_CAS)

public:
    FLock_CAS()
        :IFLockObject(eCAS)
    {}
    operator FLock_CAS* ()
    {
        return this;
    }
    virtual void Lock()
    {
    }
    virtual bool TryLock()
    {
        Lock();
        return true;
    }
    virtual void Unlock()
    {
    }
};
#endif


//----------------------------------------------------------------
// 函数自动锁
//----------------------------------------------------------------
class FLock_Auto
{
    IFLockObject* cs_lock;

public:
    // 构造时自动锁定，需要手动初始化锁对象
    FLock_Auto(IFLockObject* lock)
        :cs_lock(lock)
    {
        if (cs_lock && cs_lock->GetType() != IFLockObject::eNil)
            cs_lock->Lock();
    }
    // 析构时自动解锁，需要手动释放锁对象
    ~FLock_Auto()
    {
        if (cs_lock && cs_lock->GetType() != IFLockObject::eNil)
            cs_lock->Unlock();
    }
};


//----------------------------------------------------------------
// 基本锁对象
//----------------------------------------------------------------
#if FUEL_OS_WINDOWS
typedef FLock_CS FLockObject;
#else
typedef FLock_linux FLockObject;
#endif


#pragma pack(pop)
